package com.sparrow.common.thread;

import com.sparrow.common.thread.executor.EventExecutor;
import com.sparrow.common.thread.runnable.NamedRunnable;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.ScheduledFuture;
import io.netty.util.concurrent.SingleThreadEventExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

/**
 * ID 线程池（业务线程池，处理业务逻辑时应避免进行 I/O 操作，I/O 操作建议使用 I/O 线程池）
 */
public class IdExecutorGroup implements DisposableBean {

    // 日志记录器，用于记录线程池的相关信息和异常
    private static final Logger logger = LoggerFactory.getLogger(IdExecutorGroup.class);

    // 存储事件执行器的数组
    private final EventExecutor[] group;

    // 构造函数，目前为空，可根据需要添加初始化逻辑
    public IdExecutorGroup() {
        this(Runtime.getRuntime().availableProcessors() * 2);
    }

    public IdExecutorGroup(int threadNum) {
        group = new EventExecutor[threadNum];
        for (int i = 0; i < threadNum; i++) {
            group[i] = new EventExecutor();
        }
    }
    /**
     * 根据给定的 ID 获取对应的事件执行器
     *
     * @param id 用于分配执行器的 ID
     * @return 对应的事件执行器
     */
    public EventExecutor takeExecutor(long id) {
        return group[(int) (id % group.length)];
    }

    /**
     * 在指定 ID 对应的执行器上执行给定的任务
     *
     * @param id       用于分配执行器的 ID
     * @param runnable 要执行的任务
     */
    public void execute(String name, long id, Runnable runnable) {
        SingleThreadEventExecutor executor = takeExecutor(id);
        executor.execute(() -> {
            try {
                runnable.run();
            } catch (Throwable t) {
                // 记录执行任务时发生的异常
                logger.error("执行任务 {} 错误", name, t);
            }
        });
    }

    /**
     * 提交一个命名任务到指定 ID 对应的执行器
     *
     * @param id       用于分配执行器的 ID
     * @param taskName 任务的名称
     * @param runnable 要执行的任务
     * @return 任务的未来结果
     */
    public Future<?> submitTask(long id, String taskName, Runnable runnable) {
        SingleThreadEventExecutor executor = takeExecutor(id);
        return executor.submit(new NamedRunnable(taskName, runnable));
    }

    /**
     * 安排一个命名任务在指定延迟后执行
     *
     * @param id       用于分配执行器的 ID
     * @param taskName 任务的名称
     * @param command  要执行的任务
     * @param delay    延迟时间
     * @param unit     延迟时间的单位
     * @return 定时任务的未来结果
     */
    public ScheduledFuture<?> schedule(long id, String taskName, Runnable command, long delay, TimeUnit unit) {
        SingleThreadEventExecutor executor = takeExecutor(id);
        return executor.schedule(new NamedRunnable(taskName, command), delay, unit);
    }

    /**
     * 安排一个命名的可调用任务在指定延迟后执行
     *
     * @param id       用于分配执行器的 ID
     * @param taskName 任务的名称
     * @param callable 要执行的可调用任务
     * @param delay    延迟时间
     * @param unit     延迟时间的单位
     * @param <V>      可调用任务的返回类型
     * @return 定时任务的未来结果
     */
    public <V> ScheduledFuture<V> schedule(long id, String taskName, Callable<V> callable, long delay, TimeUnit unit) {
        SingleThreadEventExecutor executor = takeExecutor(id);
        return executor.schedule(() -> {
            try {
                return callable.call();
            } catch (Throwable t) {
                // 记录任务执行时发生的异常
                logger.error("任务: " + taskName + " 执行出错!", t);
                throw new RuntimeException("任务: " + taskName + " 执行出错!", t);
            }
        }, delay, unit);
    }

    /**
     * 安排一个命名任务以固定速率执行
     *
     * @param id            用于分配执行器的 ID
     * @param taskName      任务的名称
     * @param command       要执行的任务
     * @param initialDelay  初始延迟时间
     * @param period        执行周期
     * @param unit          时间单位
     * @return 定时任务的未来结果
     */
    public ScheduledFuture<?> scheduleAtFixedRate(long id, String taskName, Runnable command, long initialDelay, long period, TimeUnit unit) {
        SingleThreadEventExecutor executor = takeExecutor(id);
        return executor.scheduleAtFixedRate(new NamedRunnable(taskName, command), initialDelay, period, unit);
    }

    /**
     * 安排一个命名任务以固定延迟执行
     *
     * @param id            用于分配执行器的 ID
     * @param taskName      任务的名称
     * @param command       要执行的任务
     * @param initialDelay  初始延迟时间
     * @param delay         延迟时间
     * @param unit          时间单位
     * @return 定时任务的未来结果
     */
    public ScheduledFuture<?> scheduleWithFixedDelay(int id, String taskName, Runnable command, long initialDelay, long delay, TimeUnit unit) {
        SingleThreadEventExecutor executor = takeExecutor(id);
        return executor.scheduleWithFixedDelay(new NamedRunnable(taskName, command), initialDelay, delay, unit);
    }

    /**
     * 优雅地关闭线程池
     */
    public void shutdown() {
        List<Future<?>> futureList = new ArrayList<>();
        for (EventExecutor executor : group) {
            Future<?> f = executor.shutdownGracefully();
            futureList.add(f);
        }
        for (Future<?> future : futureList) {
            try {
                // 等待每个执行器关闭，最多等待 20 分钟
                future.await(20, TimeUnit.MINUTES);
            } catch (InterruptedException e) {
                // 恢复中断状态
                Thread.currentThread().interrupt();
                // 记录中断异常
                logger.error("关闭线程池时被中断", e);
            } catch (Throwable e) {
                // 记录其他异常
                logger.error("关闭线程池时发生错误", e);
                throw new RuntimeException(e);
            }
        }
        // 记录线程池关闭信息
        logger.info("业务线程池 IdExecutorGroup 已关闭");
    }

    /**
     * 实现 DisposableBean 接口的方法，在 Bean 销毁时调用
     *
     * @throws Exception 销毁过程中可能抛出的异常
     */
    @Override
    public void destroy() throws Exception {
        shutdown();
        logger.info("Id线程池关闭");
    }
}